// Effective C++ 条款38：通过复合塑模出has-a或"根据某物实现出"

// 核心原则
// 条款38的核心是："通过复合塑模出has-a或'根据某物实现出'"（Model "has-a" or "is-implemented-in-terms-of" through composition）。
// 详细解释
// 复合与继承的区别
// 在面向对象设计中，有两种主要的关系类型：
//      1."is-a"（是一种）关系：通过继承实现
//      2."has-a"（有一个）关系：通过复合（组合）实现

// 还有一种特殊的关系： 3. "is-implemented-in-terms-of"（根据某物实现出）关系：也通过复合实现，但更侧重于实现细节而非概念关系

// "has-a"关系
// "has-a"关系表示一个类包含另一个类的对象作为其成员。这反映了现实世界中的包含关系。
class Address
{
    // 地址相关属性和方法
};

class Person
{
private:
    std::string name;
    Address homeAddress; // Person "has-a" Address
    Address workAddress; // 一个人有家庭地址和工作地址
};
// 在这个例子中，Person类有两个Address对象作为成员，表示一个人有家庭地址和工作地址。

// "is-implemented-in-terms-of"关系
// 这种关系表示一个类在实现上使用了另一个类，但在概念上并不包含它。这通常是一种实现细节，而非领域模型中的概念关系。
class Set
{
private:
    std::list<int> rep; // Set is-implemented-in-terms-of list
public:
    bool contains(int x) const
    {
        return std::find(rep.begin(), rep.end(), x) != rep.end();
    }

    void insert(int x)
    {
        if (!contains(x))
            rep.push_back(x);
    }

    void remove(int x)
    {
        auto it = std::find(rep.begin(), rep.end(), x);
        if (it != rep.end())
            rep.erase(it);
    }
};
// 在这个例子中，Set类在实现上使用了std::list，但在概念上，集合并不"有一个"列表，而是"根据列表实现出来的"。

// 为什么选择复合而非继承
// 当我们错误地使用继承来表示"has-a"或"is-implemented-in-terms-of"关系时，会导致以下问题：

// 接口膨胀：派生类会继承基类的所有公共接口，即使有些方法对派生类没有意义
// 破坏封装：派生类可能会依赖基类的实现细节
// 语义不正确：继承表示"is-a"关系，如果实际关系是"has-a"，会导致概念混淆

// 错误使用继承的例子
// 错误：使用继承来表示"is-implemented-in-terms-of"关系
class Set : public std::list<int>
{ // 不好的设计
public:
    // 添加Set特有的功能
};

// 这种设计的问题：
// Set继承了std::list的所有方法，包括push_front、push_back等，这些方法可能会破坏集合的语义（允许重复元素）
// 如果std::list的实现改变，Set的行为也会改变
// 从概念上讲，集合不是一种列表，所以这违反了"is-a"关系

// 实际应用
// 设计决策
// 在设计类关系时，应该问自己以下问题：

// 1.新类是否真的"是一种"已有类？如果是，使用继承
// 2.新类是否"有一个"已有类的实例？如果是，使用复合表示"has-a"关系
// 3.新类是否可以"根据"已有类实现？如果是，使用复合表示"is-implemented-in-terms-of"关系

// 复合的其他优势
// 1.更好的封装：复合允许你只暴露需要的接口，隐藏实现细节
// 2.更灵活的设计：可以更容易地更改实现，而不影响客户代码
// 3.避免脆弱基类问题：不依赖基类的实现细节
// 4.更精确的语义：清晰地表达类之间的实际关系

// 总结
// 条款38强调了在面向对象设计中正确使用复合来表示"has-a"和"is-implemented-in-terms-of"关系的重要性。
// 使用继承表示"is-a"关系
// 使用复合表示"has-a"关系
// 使用复合表示"is-implemented-in-terms-of"关系
// 正确选择类之间的关系类型，可以创建更清晰、更灵活、更易于维护的设计。